<template>
  <div class="map_demo">
    <div class="left">
      <div class="btn" @click="showIcon">在地图上显示点</div>
      <div class="btn" @click="moveToPoint(113.89000, 22.53439)">移动到深圳前海</div>
      <div class="btn" @click="moveToPoint(113.57199, 22.27421)">移动到初始点</div>
      <div class="btn" @click="trajectory">显示一段轨迹</div>
      <div class="btn" @click="showRange">显示一个区域</div>
      <div class="btn">清除所有轨迹</div>
    </div>
    <div class="right_map">
      <div id="map"></div>
      <!-- 鼠标经纬度指示 -->
      <div id="mouse-position">
        <div class="position_lable">当前坐标</div>
      </div>
      <div class="work-box">
        <div class="tool">
          <div v-for="(n, i) in toolData" :key="i">
            <span>{{ n.title }}</span>
            <div>
              <span
                :style="{ color: toolsindex == `${i}${l}` ? '#409EFF' : '' }"
                v-for="(e, l) in n.data"
                :key="l"
                @click="clickTool(e, i, l)"
                >{{ e.title }}</span
              >
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted, nextTick } from "vue";
import { getTopLeft, getWidth } from "ol/extent";
import { getArea, getLength } from "ol/sphere";
import { Map, View, Feature, Overlay } from "ol";
import { Draw, Modify, Snap } from "ol/interaction";
import { Circle as CircleGeo } from "ol/geom";
import { Circle, Fill, Stroke, Style, Text, Icon } from "ol/style";
import { Tile, Vector as VectorLayer } from "ol/layer";
import { defaults, MousePosition } from "ol/control";
import { get, fromLonLat } from "ol/proj";
import WMTSTileGrid from "ol/tilegrid/WMTS";
import { createStringXY } from "ol/coordinate";
import { WMTS, Vector as VectorSource } from "ol/source";
import { LineString, Point, Polygon } from "ol/geom";
import { createBox, createRegularPolygon } from "ol/interaction/Draw";
import CircleStyle from "ol/style/Circle";
import { unByKey } from "ol/Observable";
const startImg = require("@/assets/imgs/start.png"); //轨迹起点图标
const endImg = require("@/assets/imgs/end.png"); //轨迹终点图标
let exportMap =ref(null);
const state=reactive({
  shapeType:'',
  layerIndex:0,
  drawCache:[],
  helpTooltip:'',
  continueLineMsg:'',
  helpTooltipElement:null,
  measureTooltipElement:null,
  measureTooltip:null,
  sketch:null,
  listener:null,

  //路径相关
  routeMap:[],

})
let toolsindex = ref(null);
const data = ref([
  {
    id: 14,
    name: "日月贝",
    longitude: "113.58383",
    latitude: "22.28709",
    pointList: [
      [113.58383, 22.28709],
      [113.58483, 22.2832],
      [113.58008, 22.2786],
    ],
  },
  {
    id: 14,
    name: "渔女",
    longitude: "113.58321",
    latitude: "22.26537",
    pointList: [
      [113.58321, 22.26537],
      [113.58321, 22.26445],
      [113.5824, 22.26308],
      [113.58038, 22.26324],
    ],
  },
]);

const toolData = ref([
  {
    title: "基础",
    key: 0,
    data: [{ title: "测量距离" }, { title: "测量面积" }, { title: "清除测量" }],
  },
  {
    title: "消防",
    key: 1,
    data: [
      { title: "画笔" },
      { title: "隔离带" },
      { title: "线选" },
      { title: "框选" },
      { title: "多边形选" },
      { title: "圈选" },
      { title: "清除" },
    ],
  },
]);

/** 左侧操作事件 */
// 显示标记点
const showIcon = () => {
  data.value.forEach((item) => {
    nextTick(() => {
      lastShowPoints(data.value, "icon.png", 0.05, (item) => {
        return {
          show: [
            `${item.name}`,
            `纬度：${item.latitude}，经度：${item.longitude}`,
          ],
          data: item,
          popupClass: "popup-box-right",
          bottom: "-13vh",
          left: "15px",
          button: true, //地图弹窗是否显示按钮
          buttonText: "点击", //地图弹窗按钮文字
          circle: true, //是否展示范围
        };
      });
    });
  });
};
// 在页面上展示点
const lastShowPoints = (dataList, imgStr, scale = 1, fn) => {
  if (dataList.length === 0) return;
  try {
    let features = []; // 定义坐标s
    imgStr = require(`../assets/imgs/${imgStr}`);
    let vectorLayer = new VectorLayer({
      renderBuffer: 200,
      source: new VectorSource(),
      style: () => [
        new Style({
          image: new Icon({
            src: imgStr,
            scale: scale,
            // imgSize: [50, 50],
          }),
        }),
      ],
    });
    // console.log('points',dataList);
    dataList.forEach((item) => {
      item.sol = fn(JSON.parse(JSON.stringify(item)));
      if ((item.lng || item.longitude) && (item.lat || item.latitude)) {
        let newObj = Object.assign({}, item);
        const wz = [
          +item.lng ? item.lng : item.longitude,
          +item.lat ? item.lat : item.latitude,
        ];
        console.log("wz", wz);
        newObj.geometry = new Point(wz);
        features.push(new Feature(newObj));
        if (item.sol.circle) {
          let circleFeature = new Feature({
            //添加面
            geometry: new CircleGeo([wz[0] * 1, wz[1] * 1], 0.005),
          });
          circleFeature.setStyle(
            new Style({
              // 设置样式
              fill: new Fill({
                color: "rgba(255, 255, 255, 0.1)",
              }),
              stroke: new Stroke({
                color: "rgba(217, 11, 53, 0.4)",
                lineDash: [20, 10],
              }),
            })
          );
          features.push(circleFeature);
        }
      }
    });
    vectorLayer.getSource().addFeatures(features);
    map.addLayer(vectorLayer);
    return vectorLayer;
  } catch (error) {
    console.log(error);
  }
};

// 移动到指定中心点位
const moveToPoint = (x, y)=>{
  map.getView().animate({
    center: [x, y],
  });
}
//显示轨迹
function trajectory() {
  let gis = [
    [113.57219, 22.27128],
    [113.57322, 22.27231],
    [113.57596, 22.27029],
    [113.57673, 22.26249],
    [113.57230, 22.25701],
    [113.57167, 22.25617],
    [113.56742, 22.24146],
    [113.56856, 22.24070]
  ];
  showWay({
    id: 11, //id
    gis: gis,
    name: "轨迹", //
  });
}

/**  ===路径相关方法======================================================================= */
// 开始显示一条轨迹
const  showWay = async (_routeInfo)=>{  
  if (state.routeMap.some((route) => route.id === _routeInfo.id)) {
    // 已经有了路径，直接移动视野到该点
    moveToPoint(_routeInfo.gis[0][0], _routeInfo.gis[0][1]);
    return;
  }
  
  // 根据一系列点设置地图视野中点
  const point = _routeInfo.gis[0];

  // 将地图设置到最大缩放度
  const view = map.getView();
  const MaxZoom = view.getMaxZoom();
  // const MinZoom = view.getMinZoom();
  // const zoom = Math.ceil((MaxZoom + MinZoom) / 1);
  view.setZoom(MaxZoom - 3);

  await moveToPoint(point[0], point[1]);

  showRouterMap(_routeInfo);
}

// 路径显示
const showRouterMap=(_routeInfo)=>{
  let pointsList = _routeInfo.gis;
  // pointsList.map(n=>{
  //   n=[1*n[0],1*n[1]]
  // })
  let roadLine = new LineString(pointsList);
  let output=formatLength(roadLine)
  console.log('output',pointsList,output);
  
  let roadLineSource = new VectorSource({
    features: [new Feature(roadLine)],
  });
  const roadLineLayer = new VectorLayer({
    source: roadLineSource,
    style: new Style({
      stroke: new Stroke({
        color: "#38A0FF",
        width: 4,
      }),
    }),
  });
  map.addLayer(roadLineLayer);
  let pointLayer1 = addVectorLabel({
    pointsList: pointsList[0],
    txt: "起",
  });
  let pointLayer2 = addVectorLabel({
    pointsList: pointsList[pointsList.length - 1],
    txt: "终",
  });
  let label = addVectorLabel({
    pointsList: [pointsList[0][0], pointsList[0][1]],
    txt: _routeInfo.name + "，全程" + output
  });

  // 保存实例
  state.routeMap.push({
    id: _routeInfo.id,
    routeLayerExample: roadLineLayer,
    vectorLabels: [label],
    points: [pointLayer1, pointLayer2],
  });
}

// 格式化路径长度显示
const formatLength=(line)=>{
  const sourceProj = exportMap.value.getView().getProjection(); //获取投影坐标系
  let length = getLength(line, { projection: sourceProj });
  let output;
  // 如果距离超过1km用km做为单位显示，否则就用m显示
  if (length >= 1000) {
    output = Math.round((length / 1000) * 100) / 100 + " " + "km";
  } else {
    output = Math.round(length * 100) / 100 + " " + "m";
  }
  return output;
}

// 添加矢量标签（例如路径的起终点、描述）
const addVectorLabel=(opt)=>{
  let vectorSource = new VectorSource(); //矢量标注的数据源
  const layer = new VectorLayer({
    source: vectorSource,
  }); //矢量标注图层
  map.addLayer(layer);
  if (opt.txt == "起" || opt.txt == "终") {
    // 添加起点以及终点的layer
    let newFeature = new Feature({
      geometry: new Point(opt.pointsList || []),
    });
    newFeature.setStyle(
      // 设置起点/终点的图标及位置
      new Style({
        image: new Icon({
          src: opt.txt == "起" ? startImg : endImg,
          offset: [0, -46], // 第一个参数负左正右，第二个参数负上正下
          offsetOrigin: "bottom-right", // 偏移位置: bottom-left, bottom-right, top-left, top-right.
          scale: 0.5, // 图片缩放
          size: [42, 100], // 图片渲染区域大小
        }),
        fill: new Fill({ color: "#ffffff" }),
        zIndex: 1,
      })
    );
    // 将新要素添加到数据源中
    vectorSource.addFeature(newFeature);
    return layer;
  }
  let overlayerElement = document.createElement("div");
  overlayerElement.className = "ol-tooltip-draw-route";
  overlayerElement.innerHTML = opt.txt;
  const overlayObj = new Overlay({
    element: overlayerElement,
    offset: [0, -50],
    positioning: "bottom-center",
  });
  overlayObj.setPosition(opt.pointsList);
  map.addOverlay(overlayObj);
  return overlayObj;
}

/**  ===区域相关方法======================================================================= */
// 展示范围的点击事件
const showRange = () => {
  groupPlot(data.value)
}
//点数组绘图
const groupPlot = (data, color, borderColor)=>{
  console.log("🚀 ~ groupPlot ~ data:", data)
  console.log(color);
  color=color || "rgba(252, 51, 40, 0.2700)"
  let source = new VectorSource();
  let style = new Style({
    text: new Text({
        // font: '15px Microsoft YaHei',
        // text:'xxxx',
        fill: new Fill({
          color: '#fff'
        })
    }),
    fill: new Fill({
        color
    }),
    stroke: new Stroke({
        color: borderColor || 'rgba(252, 51, 40, 1)',
        width:  2
    }),
    image: new Circle({
        radius: 10,
        fill: new Fill({
            color: '#ffcc33'
        })
    })
  });
  //矢量图层
  let vectorLayer = new VectorLayer({
      source: source,
      style: style,
  });    
  let features = [];
 
  //多边形要素类
  data.map((n)=>{
    //声明一个新的数组
    let coordinatesPolygon = new Array();
    
    //循环遍历将经纬度转到"EPSG:4326"投影坐标系下
    for (let i = 0; i < n.pointList.length; i++) {
        let pointTransform = fromLonLat([n.pointList[i][0], n.pointList[i][1]], "EPSG:4326");
        coordinatesPolygon.push(pointTransform);
    }
    let feature = new Feature({
        ...n,
        geometry: new Polygon([coordinatesPolygon]),//多边形此处注意一定要是[坐标数组]
    });
    features.push(feature)
  })
  
  source.addFeatures(features);
  map.addLayer(vectorLayer);
  // saveGroupLayer.value=vectorLayer;
  return vectorLayer
}

// function clearTrajectory() {
//   (mapRef.value as any).clearRoute(11);
// }

// //地图上显示范围
// function range() {
//   nextTick(() => {
//     groupPlot(data.value);
//   });
// }

// //画线
// const drawLine=(bool)=>{
//     draw.value && map.removeInteraction(draw.value);
//     draw.value = new Draw({
//       source:drawVector.getSource(),
//       type: "LineString",
//       freehand: bool,
//       stopClick: true,
//     });
//     exportMap.value.addInteraction(draw.value);
//     draw.value && draw.value.on('drawend',() =>drawList.value.push(draw.value))
//     // console.log('drawVector',drawVector);
//     return draw.value;
// }

// // 多边形
// const drawPolygon=()=>{
//   draw.value && map.removeInteraction(draw.value);
//   draw.value = new Draw({
//     source: drawVector.getSource(),
//     type: "Polygon",
//     stopClick: true,
//   });
//   exportMap.value.addInteraction(draw.value);
//   draw.value && draw.value.on('drawend',() =>drawList.value.push(draw.value))
// }

// 点击控制器
function clickTool(n, i, l) {
  console.log("🚀 ~ clickTool ~ n, i, l:", n, i, l);
}

let map = undefined;

// 初始化地图控制器
function getIninialControl(mouseInfoTargetId = "mouse-position") {
  let mousePositionControl = new MousePosition({
    coordinateFormat: createStringXY(5),
    projection: "EPSG:4326",
    className: "custom_mouse_position",
    target: document.getElementById(mouseInfoTargetId) || undefined,
    undefinedHTML: " ",
  });
  return defaults({ zoom: false, rotate: false }).extend([
    mousePositionControl,
  ]);
}

// 地图初始化
const initMap = () => {
  try {
    let projection = get("EPSG:4326");
    let projectionExtent = projection.getExtent();
    let size = getWidth(projectionExtent) / 256;
    let resolutions = new Array(18);
    let matrixIds = new Array(18);
    // const modify = initDrawSource();

    for (let i = 1; i <= 18; i++) {
      resolutions[i] = size / Math.pow(2, i);
      matrixIds[i] = i;
    }
    map = new Map({
      controls: getIninialControl(),
      layers: [
        // 卫星图层数据
        new Tile({
          source: new WMTS({
            url: "http://t{0-7}.tianditu.gov.cn/img_c/wmts?tk=7364af55ce18bfbd3038cdc2d28bc253", //这里是你申请的key
            layer: "img",
            style: "default",
            matrixSet: "c",
            projection: projection,
            format: "tiles",
            tileGrid: new WMTSTileGrid({
              origin: getTopLeft(projectionExtent),
              resolutions: resolutions,
              matrixIds: matrixIds,
            }),
            wrapX: true,
          }),
        }),
        // 卫星行政数据
        new Tile({
          source: new WMTS({
            url: "http://t{0-7}.tianditu.gov.cn/cia_c/wmts?tk=7364af55ce18bfbd3038cdc2d28bc253", //这里是你申请的key
            layer: "cia", //vec/cva img/cia
            matrixSet: "c",
            format: "tiles",
            style: "default",
            projection: projection,
            tileGrid: new WMTSTileGrid({
              origin: getTopLeft(projectionExtent),
              resolutions: resolutions,
              matrixIds: matrixIds,
            }),
            wrapX: true,
          }),
        }),
        // drawVector,
      ],
      target: "map",
      view: new View({
        center: [113.57199, 22.27421], // 初始化中心点 南油大酒店
        maxZoom: 18,
        minZoom: 3,
        zoom: 15, //地图层级
        projection: "EPSG:4326",
      }),
    });
    map.on('loadend', () => {
      const view = map.getView();
      console.log("🚀 ~ map.on ~ view:", view)
    })
    exportMap.value=map
    // map.addInteraction(modify);
  } catch (err) {
    console.log(err);
  }
};

onMounted(() => {
  initMap();
});
</script>
<style scoped lang="scss">
.map_demo {
  width: 100;
  height: 100%;
  background-color: #f5f5f5;
  display: flex;
  .left {
    width: 300px;
    padding: 32px 20px 0 20px;
    border-right: 1px solid #b6b1b1;
    .btn {
      text-align: center;
      color: #fff;
      background-color: rgb(97, 97, 236);
      padding: 8px 0 8px;
      border-radius: 4px;
      margin-bottom: 12px;
      cursor: pointer;
    }
  }
  .right_map {
    flex-grow: 1;
    height: 100%;
    position: relative;
    #map {
      height: 100%;
      :deep(.ol-tooltip-draw-route) {
        padding: 12px;
        background: rgba($color: #000000, $alpha: 0.3);
        color: #fff;
      }
    }
    #mouse-position {
      position: absolute;
      bottom: 20px;
      left: 60px;
      color: #fff;
      display: flex;
      z-index: 999;
      font-size: 16px;
      font-weight: 700;
      .position_lable {
        padding-right: 8px;
      }
      :deep(.custom_mouse_position) {
        font-size: 14px;
        font-weight: normal;
      }
    }
  }
}
.work-box {
  display: flex;
  align-items: center;
  color: #fff;
  position: absolute;
  bottom: 78px;
  left: 30px;
  .tool {
    position: absolute;
    // bottom: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    border: 1px solid;
    margin: 0 20px;
    background: gray;
    border-radius: 5px;
    padding-bottom: 32px;
    > * {
      padding: 0 10px;
      display: flex;
      width: 510px;
      align-items: center;
      > span {
        font-size: 16px;
        font-weight: 700;
      }
      > div:first-child {
        border-bottom: 1px solid;
      }
      > div {
        margin: 3px 10px;
        display: flex;
        flex: 1;
        justify-content: space-around;
        span {
          display: inline-block;
          padding: 8px;
          border: 1px solid;
          cursor: pointer;
          margin: 3px 5px;
          font-size: 14px;
          border-radius: 5px;
        }
      }
    }
  }
}
</style>
